package com.yungu.swift.admin.route.operation;

import com.alibaba.dubbo.config.annotation.Reference;
import com.yungu.swift.admin.base.CurrentUser;
import com.yungu.swift.admin.consts.AdminErrorEnum;
import com.yungu.swift.admin.route.helper.DataListHelper;
import com.yungu.swift.admin.utils.DownloadUtils;
import com.yungu.swift.admin.utils.RandomCipherUtils;
import com.yungu.swift.admin.utils.UploadUtils;
import com.yungu.swift.admin.utils.WorkbookUtil;
import com.yungu.swift.assets.driver.model.dto.CarDto;
import com.yungu.swift.assets.driver.model.dto.CarInsuranceDto;
import com.yungu.swift.assets.driver.model.dto.CarModelDto;
import com.yungu.swift.assets.driver.model.dto.DriverDto;
import com.yungu.swift.assets.driver.model.param.AdminCarNumParam;
import com.yungu.swift.assets.driver.model.param.AdminCarPageParam;
import com.yungu.swift.assets.driver.model.param.AdminCarParam;
import com.yungu.swift.assets.driver.model.vo.AdminCarDetailVo;
import com.yungu.swift.assets.driver.model.vo.CarExportVo;
import com.yungu.swift.assets.driver.model.vo.CarImportVo;
import com.yungu.swift.assets.driver.service.CarInsuranceService;
import com.yungu.swift.assets.driver.service.CarService;
import com.yungu.swift.assets.driver.service.DriverService;
import com.yungu.swift.base.ResponseData;
import com.yungu.swift.base.model.PageVo;
import com.yungu.swift.base.model.admin.AdminParam;
import com.yungu.swift.base.model.admin.AdminUuidParam;
import com.yungu.swift.base.model.annotation.ResponseImgOverride;
import com.yungu.swift.constants.CommonConstant;
import com.yungu.swift.system.sys.model.dto.SysBusinessDto;
import com.yungu.swift.system.sys.model.dto.SysCompanyDto;
import com.yungu.swift.system.sys.model.dto.SysRegionalAgentDto;
import com.yungu.swift.utils.MapUtils;
import com.yungu.swift.utils.ParamUtil;
import com.yungu.swift.utils.StringUtils;
import com.yungu.swift.utils.ValidateUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.nio.charset.Charset;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

/**
 * @author : cuixiuyin
 * @date : 2019/6/24
 */
@Slf4j
@RestController
@RequestMapping("/admin/v1/operation/car")
@Api(value = "【运营管理】", tags = "车辆信息管理")
@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class CarAdmin {

    @Reference
    private CarService carService;
    @Reference
    private DriverService driverService;
    @Reference
    private CarInsuranceService carInsuranceService;

    /**
     * 错误的行数
     */
    private Set<Integer> errSet;

    /**
     * 导入模板
     */
    private Workbook workbook;

    /**
     * 导入模板名
     */
    private String fileName;

    @ResponseImgOverride
    @RequestMapping(value = "/queryPage", method = RequestMethod.POST)
    @ApiOperation(value = "车辆信息分页查询", httpMethod = "POST")
    public ResponseData<PageVo<CarDto>> queryPage(@RequestBody AdminCarPageParam carPageParam) {
        if (ParamUtil.isIllegal(carPageParam.getBusinessType())) {
            return ResponseData.buildErrorResponse(AdminErrorEnum.PARAM_ERROR.getCode(), AdminErrorEnum.PARAM_ERROR.getMsg());
        }
        return carService.queryPage(carPageParam);
    }

    @RequestMapping(value = "/del", method = RequestMethod.POST)
    @ApiOperation(value = "车辆删除，仅删除未绑定司机车辆", httpMethod = "POST")
    public ResponseData<Boolean> del(@RequestBody AdminUuidParam adminUuidParam) {
        if (ParamUtil.isIllegal(adminUuidParam.getUuid())) {
            return ResponseData.buildErrorResponse(AdminErrorEnum.PARAM_ERROR.getCode(), AdminErrorEnum.PARAM_ERROR.getMsg());
        }
        //存在司机信息不允许删除
        ResponseData<List<DriverDto>> driverListExtend = driverService.listExtend(MapUtils.build("carUuid", adminUuidParam.getUuid()));
        if (driverListExtend.isSuccess() && CollectionUtils.isNotEmpty(driverListExtend.getData())) {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "车辆已绑定司机，不允许删除");
        }
        return carService.del(adminUuidParam.getUuid(), CarDto.class);
    }

    @ResponseImgOverride
    @RequestMapping(value = "/detail", method = RequestMethod.GET)
    @ApiOperation(value = "车辆信息详情（包括车辆信息和关联司机信息）", httpMethod = "GET")
    public ResponseData<AdminCarDetailVo> detail(@RequestParam String uuid) {
        if (ParamUtil.isIllegal(uuid)) {
            return ResponseData.buildErrorResponse(AdminErrorEnum.PARAM_ERROR.getCode(), AdminErrorEnum.PARAM_ERROR.getMsg());
        }
        AdminCarDetailVo adminCarDetailVo = new AdminCarDetailVo();
        //车辆信息
        ResponseData<List<CarDto>> carListExtend = carService.listExtend(MapUtils.build("uuid", uuid));
        if (carListExtend.isSuccess() && CollectionUtils.isNotEmpty(carListExtend.getData())) {
            CarDto carDto = carListExtend.getData().get(0);
            ResponseData<List<CarInsuranceDto>> insuranceList = carInsuranceService.list(MapUtils.build("carUuid", carDto.getUuid()));
            if(CollectionUtils.isNotEmpty(insuranceList.getData())){
                carDto.setCarInsuranceList(insuranceList.getData());
            }
            adminCarDetailVo.setCarDto(carDto);
        }
        //司机信息
        ResponseData<List<DriverDto>> driverListExtend = driverService.listExtend(MapUtils.build("carUuid", uuid));
        if (driverListExtend.isSuccess() && CollectionUtils.isNotEmpty(driverListExtend.getData())) {
            adminCarDetailVo.setDriverDto(driverListExtend.getData().get(0));
        }
        return ResponseData.buildSuccessResponse(adminCarDetailVo);
    }


    @ResponseImgOverride
    @RequestMapping(value = "/getByPlateNum", method = RequestMethod.GET)
    @ApiOperation(value = "通过车牌号得到车辆信息", httpMethod = "GET")
    public ResponseData<CarDto> getByPlateNum(@RequestParam String plateNum) {
        if (ParamUtil.isIllegal(plateNum)) {
            return ResponseData.buildErrorResponse(AdminErrorEnum.PARAM_ERROR.getCode(), AdminErrorEnum.PARAM_ERROR.getMsg());
        }
        return carService.get(MapUtils.build("plateNum", plateNum));
    }


    @RequestMapping(value = "/plateNumOnly", method = RequestMethod.POST)
    @ApiOperation(value = "校验车牌号是否唯一", httpMethod = "POST")
    public boolean plateNumOnly(@RequestBody AdminCarNumParam plateNumParam) {
        ResponseData<List<CarDto>> responseData = carService.list(MapUtils.build("plateNum", plateNumParam.getPlateNum()));
        if (responseData.isSuccess() && CollectionUtils.isNotEmpty(responseData.getData()) && responseData.getData().size() > 1) {
            return Boolean.FALSE;
        }
        return Boolean.TRUE;
    }

    @ResponseImgOverride
    @RequestMapping(value = "/saveOrUpdate", method = RequestMethod.POST)
    @ApiOperation(value = "车辆信息新增或更新", httpMethod = "POST")
    public ResponseData<Boolean> saveOrUpdate(@RequestBody AdminCarParam carParam) {
        if (ParamUtil.isIllegal(carParam.getBusinessType(), carParam.getPlateNum(), carParam.getAgentUuid(),
                carParam.getCompanyUuid(), carParam.getCarModelUuid())) {
            return ResponseData.buildErrorResponse(AdminErrorEnum.PARAM_ERROR.getCode(), AdminErrorEnum.PARAM_ERROR.getMsg());
        }
        boolean flag;
        switch (carParam.getBusinessType()) {
            case CommonConstant.BUSINESS_TYPE_TAXI:
                flag = ParamUtil.isIllegal(carParam.getDrivingLicenseImg(), carParam.getDrivingLicenseSubImg(),
                        carParam.getCertificate(), carParam.getOperationCertificateImg(), carParam.getMonitoringCardImg(),
                        carParam.getManCarImg());
                break;
            default:
                flag = ParamUtil.isIllegal(carParam.getModel(), carParam.getBrand(), carParam.getCarColor(),
                        carParam.getSeats(), carParam.getOwnerName(), carParam.getOwnerNameMobile());
                break;
        }
        if (flag) {
            return ResponseData.buildErrorResponse(AdminErrorEnum.PARAM_ERROR.getCode(), AdminErrorEnum.PARAM_ERROR.getMsg());
        }
        CarDto carDto = new CarDto();
        BeanUtils.copyProperties(carParam, carDto);
        // 加密信息
        if (carDto.getPlateNum() != null) {
            carDto.setPlateNum(RandomCipherUtils.randomDecrypt(carDto.getPlateNum()));
        }
        if (carDto.getDrivingLicenseNo() != null) {
            carDto.setDrivingLicenseNo(RandomCipherUtils.randomDecrypt(carDto.getDrivingLicenseNo()));
        }
        if (carDto.getOwnerName() != null) {
            carDto.setOwnerName(RandomCipherUtils.randomDecrypt(carDto.getOwnerName()));
        }
        if (carDto.getOwnerNameMobile() != null) {
            carDto.setOwnerNameMobile(RandomCipherUtils.randomDecrypt(carDto.getOwnerNameMobile()));
        }
        if (carDto.getCertificate() != null) {
            carDto.setCertificate(RandomCipherUtils.randomDecrypt(carDto.getCertificate()));
        }
        // 保险信息
        List<AdminCarParam.CarInsuranceParam> carInsuranceParams = carParam.getCarInsuranceParamList();
        if (CollectionUtils.isNotEmpty(carInsuranceParams)) {
            List<CarInsuranceDto> collect = carInsuranceParams.stream().map(carInsuranceParam -> {
                CarInsuranceDto insuranceDto = new CarInsuranceDto();
                BeanUtils.copyProperties(carInsuranceParam, insuranceDto);
                return insuranceDto;
            }).collect(Collectors.toList());
            carDto.setCarInsuranceList(collect);
        }
        carDto.setState(1);
        String uuid = carParam.getUuid();
        if (StringUtils.isNotEmpty(uuid)) {
            carDto.setUpdateBy(carParam.getUserUuid());
            return carService.edit(carDto);
        }
        carDto.setUuid(StringUtils.buildUUID());
        carDto.setCreateBy(carParam.getUserUuid());
        return carService.add(carDto);
    }


    @RequestMapping(value = "/downloadExcelTemplate", method = RequestMethod.GET)
    @ApiOperation(value = "下载 Excel 导入模板", httpMethod = "GET")
    public void downloadExcelTemplate(HttpServletResponse response, @RequestParam Integer businessType) throws IOException {
        InputStream in;
        String fileName;
        switch (businessType) {
            case 1:
                in = getClass().getResourceAsStream("/template/taxiImport.xlsx");
                fileName = "出租车导入模板.xlsx";
                break;
            case 3:
                in = getClass().getResourceAsStream("/template/crossCarImport.xlsx");
                fileName = "拼车导入模板.xlsx";
                break;
            default:
                in = getClass().getResourceAsStream("/template/expressCarImport.xlsx");
                fileName = "专快车导入模板.xlsx";
                break;
        }
        DownloadUtils.download(response, in, fileName);
    }


    @RequestMapping(value = "/import", method = RequestMethod.POST)
    @ApiOperation(value = "车辆信息导入", httpMethod = "POST")
    @Transactional(rollbackFor = Exception.class)
    public ResponseData<Boolean> importCar(@RequestParam(value = "file") MultipartFile file,
                                           @RequestParam(value = "type") Integer businessType,
                                           @CurrentUser AdminParam adminParam) {
        // 所有待插入的车辆集合
        Map<String, CarDto> carDtoMap = new HashMap<>(2);
        // 所有待插入的车辆保险集合
        Map<String, CarInsuranceDto> carInsuranceDtoMap = new HashMap<>(2);
        // 所有待更新的车辆集合
        Map<String, CarDto> updateCarDtoMap = new HashMap<>(2);
        // 所有待更新的车辆保险集合
        Map<String, CarInsuranceDto> updateCarInsuranceDtoMap = new HashMap<>(2);

        StringBuilder errmsg = new StringBuilder();

        workbook = null;
        errSet = new HashSet<>();
        fileName = file.getOriginalFilename();
        try {
            workbook = WorkbookFactory.create(file.getInputStream());
            Sheet sheet = this.workbook.getSheetAt(0);
            if (workbook.getNumberOfSheets() > 1) {
                sheet = this.workbook.getSheet("车辆导入格式");
            }
            if (sheet == null) {
                return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "文件数据缺失");
            }
            Row firstRow = sheet.getRow(0);
            if (firstRow == null) {
                return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "文件数据缺失");
            }
            Map<String, CarModelDto> name2BeanMap = DataListHelper.getCarLevelName2BeanMap();
            Map<String, SysRegionalAgentDto> agentMap = DataListHelper.getAgentName2BeanMap();
            Map<String, SysCompanyDto> companyMap = DataListHelper.getCompanyName2BeanMap();
            Map<String, String> carPlateNum2UuidMap = DataListHelper.getCarPlateNum2UuidMap();
            Set<String> plateNumSet = DataListHelper.getCarPlateNumSet();
            for (int rowNum = 1; rowNum <= sheet.getLastRowNum(); rowNum++) {
                Row row = sheet.getRow(rowNum);
                if (row == null) {
                    continue;
                }
                // 车辆保险信息
                CarInsuranceDto carInsuranceDto;
                CarDto carDto = new CarDto();
                // 读取一行数据并保存到对象中
                CarImportVo carImportVo = readRowToBean(row);
                // 校验失败则继续读取下一行数据
                if (!validateRow(carImportVo, row, businessType)) {
                    errSet.add(rowNum);
                    continue;
                }

                // 校验业务
                // 校验车牌号
                String plateNum = carImportVo.getPlateNum();
                if (plateNumSet.contains(plateNum)) {
                    errmsg.append(plateNum + "车牌号已存在").append("\r\n");
                    errSet.add(rowNum);
                    continue;
                }
                plateNumSet.add(plateNum);
                // 校验跨城核定载客位
                CarModelDto carModelDto = name2BeanMap.get(businessType + carImportVo.getCarModelType());
                if (businessType == CommonConstant.BUSINESS_TYPE_POOL && carModelDto != null) {
                    Integer maxSeats = carModelDto.getMaxPassengerSeats();
                    //判断导入的荷载座位数是否大于该车型的最大座位数
                    if (Integer.valueOf(carImportVo.getSeats()) > maxSeats + 1) {
                        errmsg.append(carImportVo.getSeats() + "荷载座位数大于该车型的最大座位数").append("\r\n");
                        errSet.add(rowNum);
                        continue;
                    }
                }
                //校验代理
                //校验代理是否开通该业务
                String agent = carImportVo.getAgent();
                if (!agentMap.containsKey(agent)) {
                    errmsg.append(agent + "代理不存在").append("\r\n");
                    errSet.add(rowNum);
                    continue;
                } else {
                    Map<String, List<SysBusinessDto>> listBusMap = DataListHelper.getOrgUuid_ListBusMap(adminParam.getAppid());
                    List<SysBusinessDto> sysBusinessDtos = listBusMap.get(agentMap.get(agent).getUuid());
                    SysBusinessDto businessDto = sysBusinessDtos.stream().filter(
                            sysBusinessDto -> businessType.equals(sysBusinessDto.getType())).findAny().orElse(null);
                    if (businessDto == null) {
                        errmsg.append("代理没有开通该业务").append("\r\n");
                        errSet.add(rowNum);
                        continue;
                    }
                }
                carImportVo.setAgent(agentMap.get(agent).getUuid());
                //校验公司
                //校验公司是否有该业务
                String company = carImportVo.getCompany();
                if (!companyMap.containsKey(company)) {
                    errmsg.append(company + "公司不存在").append("\r\n");
                    errSet.add(rowNum);
                    continue;
                } else {
                    SysCompanyDto sysCompanyDto = companyMap.get(company);
                    if (!sysCompanyDto.getRegionalAgentUuid().equals(carImportVo.getAgent())) {
                        errmsg.append(company + "和代理不匹配").append("\r\n");
                        errSet.add(rowNum);
                        continue;
                    }
                    Map<String, List<SysBusinessDto>> listBusMap = DataListHelper.getOrgUuid_ListBusMap(adminParam.getAppid());
                    List<SysBusinessDto> sysBusinessDtos = listBusMap.get(companyMap.get(company).getUuid());
                    SysBusinessDto businessDto = sysBusinessDtos.stream().filter(
                            sysBusinessDto -> businessType.equals(sysBusinessDto.getType())).findAny().orElse(null);
                    if (businessDto == null) {
                        errmsg.append("公司没有开通该业务").append("\r\n");
                        errSet.add(rowNum);
                        continue;
                    }
                }
                carImportVo.setCompany(companyMap.get(company).getUuid());

                //校验级别类型
                String carModelType = carImportVo.getCarModelType();
                CarModelDto carLevelDto = name2BeanMap.get(businessType + carModelType);
                if (carLevelDto == null) {
                    errmsg.append(carModelType + "不存在或与业务不匹配").append("\r\n");
                    errSet.add(rowNum);
                    continue;
                }
                carImportVo.setCarModelType(carLevelDto.getUuid());
                //检验代理企业是否和绑定的司机匹配
                String carUuid = carPlateNum2UuidMap.get(carImportVo.getPlateNum());
                //车辆新增不用校验司机
                if (StringUtils.isNotEmpty(carUuid)) {
                    List<DriverDto> driverDtos = driverService.list(MapUtils.build("carUuid", carUuid)).getData();
                    log.info("carUuid={},PlateNum={},driverDtos:{}", carUuid, carImportVo.getPlateNum(), driverDtos.size());
                    if (CollectionUtils.isNotEmpty(driverDtos)) {
                        DriverDto dto = driverDtos.get(0);
                        if (!dto.getAgentUuid().equals(carImportVo.getAgent()) || !dto.getCompanyUuid().equals(carImportVo.getCompany())) {
                            errmsg.append(plateNum + "车辆的代理或企业与绑定的司机不符").append("\r\n");
                            errSet.add(rowNum);
                            continue;
                        }
                    }
                }

                carDto.setState(0);
                carDto.setCompanyUuid(carImportVo.getCompany());
                carDto.setAgentUuid(carImportVo.getAgent());
                carDto.setPlateNum(carImportVo.getPlateNum());
                if (StringUtils.isNotEmpty(carImportVo.getPlateColor())) {
                    carDto.setPlateColor(String.valueOf(carImportVo.getPlateColor().charAt(0)));
                }
                if (StringUtils.isNotEmpty(carImportVo.getSeats())) {
                    carDto.setSeats(Integer.parseInt(carImportVo.getSeats()));
                }
                carDto.setBrand(carImportVo.getBrand());
                carDto.setModel(carImportVo.getModel());
                carDto.setCarModelUuid(carImportVo.getCarModelType());
                carDto.setCarColor(carImportVo.getCarColor());
                carDto.setEngineId(carImportVo.getEngineId());
                carDto.setVin(carImportVo.getVin());
                carDto.setCertifyDateA(carImportVo.getCertifyDateA());
                if (StringUtils.isNotEmpty(carImportVo.getFuelType())) {
                    carDto.setFuelType(String.valueOf(carImportVo.getFuelType().charAt(0)));
                }
                carDto.setEngineDisplace(carImportVo.getEngineDisplace());
                if (StringUtils.isNotEmpty(carImportVo.getEnginePower())) {
                    carDto.setEnginePower(Integer.valueOf(carImportVo.getEnginePower()));
                }
                carDto.setCertificate(carImportVo.getCertificate());
                carDto.setTransAgency(carImportVo.getTransAgency());
                carDto.setTransDateStart(carImportVo.getTransDateStart());
                carDto.setTransDateStop(carImportVo.getTransDateStop());
                carDto.setCertifyDateB(carImportVo.getCertifyDateB());
                carDto.setRegisterDate(carImportVo.getRegisterDate());
                if (StringUtils.isNotEmpty(carImportVo.getCommercialType())) {
                    carDto.setCommercialType(Integer.valueOf(carImportVo.getCommercialType().charAt(0) - '0'));
                }
                if (StringUtils.isNotEmpty(carImportVo.getFixState())) {
                    carDto.setFixState(Integer.valueOf(carImportVo.getFixState().charAt(0) - '0'));
                }
                carDto.setNextFixDate(carImportVo.getNextFixDate());
                if (StringUtils.isNotEmpty(carImportVo.getCheckState())) {
                    carDto.setCheckState(Integer.valueOf(carImportVo.getCheckState().charAt(0) - '0'));
                }
                carDto.setFeePrintId(carImportVo.getFeePrintId());
                carDto.setGpsBrand(carImportVo.getGpsBrand());
                carDto.setGpsModel(carImportVo.getGpsModel());
                carDto.setGpsImei(carImportVo.getGpsImei());
                carDto.setGpsInstallDate(carImportVo.getGpsInstallDate());
                carDto.setVehicleTechnicalCondition(carImportVo.getVehicleTechnicalCondition());
                carDto.setSafetyPerformance(carImportVo.getSafetyPerformance());
                carDto.setOwnerName(carImportVo.getOwnerName());
                carDto.setOwnerNameMobile(carImportVo.getOwnerNameMobile());

                //车险
                carInsuranceDto = new CarInsuranceDto();
                carInsuranceDto.setCompanyUuid(carImportVo.getCompany());
                carInsuranceDto.setInsurCom(carImportVo.getInsurCom());
                carInsuranceDto.setInsurNum(carImportVo.getInsurNum());
                if (StringUtils.isNotEmpty(carImportVo.getInsurCount())) {
                    carInsuranceDto.setInsurCount(BigDecimal.valueOf(Double.parseDouble(carImportVo.getInsurCount())));
                }
                carInsuranceDto.setInsurType(carImportVo.getInsurType());
                carInsuranceDto.setInsurEff(carImportVo.getInsurEff());
                carInsuranceDto.setInsurExp(carImportVo.getInsurExp());

                //已存在、更新
                if (carPlateNum2UuidMap.containsKey(carImportVo.getPlateNum())) {
                    carDto.setUpdateOn(new Date());
                    carDto.setUpdateOn(new Date());
                    carDto.setUpdateBy(adminParam.getUserUuid());
                    carDto.setFlag(2);
                    carDto.setUuid(carPlateNum2UuidMap.get(carImportVo.getPlateNum()));
                    updateCarDtoMap.put(carDto.getUuid(), carDto);

                    carInsuranceDto.setCarUuid(carDto.getUuid());
                    carInsuranceDto.setUpdateOn(new Date());
                    carInsuranceDto.setUpdateBy(adminParam.getUserUuid());
                    updateCarInsuranceDtoMap.put(carInsuranceDto.getUuid(), carInsuranceDto);
                } else {//新增
                    carDto.setUuid(StringUtils.buildUUID());
                    carDto.setCreateOn(new Date());
                    carDto.setCreateOn(new Date());
                    carDto.setCreateBy(adminParam.getUserUuid());
                    carDto.setAppid(adminParam.getAppid());
                    carDtoMap.put(carDto.getUuid(), carDto);

                    // 添加车辆保险
                    carInsuranceDto.setUuid(StringUtils.buildUUID());
                    carInsuranceDto.setCarUuid(carDto.getUuid());
                    carInsuranceDto.setCreateOn(new Date());
                    carInsuranceDto.setCreateBy(adminParam.getUserUuid());
                    carInsuranceDtoMap.put(carInsuranceDto.getUuid(), carInsuranceDto);
                }
            }

            // 所有待插入的司机集合
            List<CarDto> carDtoList = new ArrayList<>(carDtoMap.values());
            // 所有待插入的司机保险集合
            List<CarInsuranceDto> carInsuranceDtoList = new ArrayList<>(carInsuranceDtoMap.values());
            // 所有待更新的司机集合
            List<CarDto> updateCarDtoList = new ArrayList<>(updateCarDtoMap.values());
            // 所有待更新的司机保险集合
            List<CarInsuranceDto> updateCarInsuranceDtoList = new ArrayList<>(updateCarInsuranceDtoMap.values());

            carService.importCar(carDtoList, carInsuranceDtoList, updateCarDtoList, updateCarInsuranceDtoList);

            //返回结果
            if (errSet.size() == 0 && StringUtils.isEmpty(errmsg.toString()) && businessType.equals(CommonConstant.BUSINESS_TYPE_TAXI)) {
                return ResponseData.buildSuccessResponse("信息导入成功 ，继续导入图片后，车辆即可开通成功", Boolean.TRUE);
            }
            if (errSet.size() == 0 && StringUtils.isEmpty(errmsg.toString()) && !businessType.equals(CommonConstant.BUSINESS_TYPE_TAXI)) {
                return ResponseData.buildSuccessResponse("信息导入成功", Boolean.TRUE);
            }
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, StringUtils.isEmpty(errmsg.toString()) ?
                    "信息填写有误，请点击下载导入结果，修改后再次导入" : errmsg.toString());
        } catch (Exception e) {
            e.printStackTrace();
            errSet = new HashSet<>();
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, "系统异常，请联系管理员解决");
        }
    }

    /**
     * 下载错误的 Excel 表格
     *
     * @return
     */
    @RequestMapping("/downloadErrorExcel")
    public void downloadErrorExcel(HttpServletRequest request, HttpServletResponse response) throws IOException {
        OutputStream os = null;
        try {
            Sheet sheet;
            int sheetCount = this.workbook.getNumberOfSheets();
            if (sheetCount > 1) {
                sheet = this.workbook.getSheet("车辆导入格式");
            } else {
                sheet = this.workbook.getSheetAt(0);
            }
            int rowNum = sheet.getLastRowNum();
            for (int i = 1; i <= rowNum; i++) {
                if (errSet.contains(i)) {
                    continue;
                } else {
                    sheet.removeRow(sheet.getRow(i));
                }
            }
            // 删除空白行
            while (sheet.getLastRowNum() != errSet.size()) {
                removeNullRow(sheet);
            }
            os = response.getOutputStream();
            response.setHeader("Content-Disposition", "attachment; filename=" + java.net.URLEncoder.encode(fileName, "UTF-8"));
            response.setContentType("application/octet-stream");
            response.setCharacterEncoding("utf-8");
            workbook.write(os);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (os != null) {
                os.close();
            }
        }
    }

    private Sheet removeNullRow(Sheet sheet) {
        int lastRowNum = sheet.getLastRowNum();
        for (int i = 0; i < lastRowNum + 1; i++) {
            Row row = sheet.getRow(i);
            if (row == null) {
                sheet.shiftRows(i + 1, lastRowNum, -1);
                break;
            }
        }
        return sheet;
    }

    @RequestMapping(value = "/downloadZipTemplate", method = RequestMethod.GET)
    @ApiOperation(value = "下载图片导入模板", httpMethod = "GET")
    public void downloadZipTemplate(HttpServletResponse response) {
        DownloadUtils.download(response, getClass().getResourceAsStream("template/D00666.zip"), "闽D00666.zip");
    }

    @RequestMapping(value = "/uploadPictures", method = RequestMethod.POST)
    @ApiOperation(value = "车辆信息图片导入", httpMethod = "POST")
    public ResponseData<Boolean> uploadPictures(@RequestPart("pictures") MultipartFile pictures,
                                                @RequestParam(required = false) String carUuid,
                                                @RequestParam(required = false) Integer businessType,
                                                @CurrentUser AdminParam adminParam) throws IOException {
        StringBuilder errmsg = new StringBuilder(16);
        final String plateNum = StringUtils.substringBefore(pictures.getOriginalFilename(), ".");
        // 用于单独的车辆图片上传
        if (StringUtils.isNotEmpty(carUuid)) {
            List<CarDto> carDtos = carService.list(MapUtils.build("uuid", carUuid)).getData();
            if (CollectionUtils.isNotEmpty(carDtos)) {
                CarDto carDto = carDtos.get(0);
                if (!plateNum.equalsIgnoreCase(carDto.getPlateNum())) {
                    errmsg.append("此压缩包命名与该车辆不符：" + plateNum).append("\r\n");
                    return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, errmsg.toString());
                }
            }
        }
        List<CarDto> carDtos = carService.listExtend(MapUtils.build("plateNum", plateNum)).getData();
        if (CollectionUtils.isNotEmpty(carDtos)) {
            CarDto carDto = carDtos.get(0);
            //判断业务
            if (!carDto.getBusinessType().equals(businessType)) {
                errmsg.append("该业务下未发现该车辆：" + plateNum).append("\r\n");
                return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, errmsg.toString());
            }
            ZipInputStream zipInputStream = new ZipInputStream(pictures.getInputStream(), Charset.forName("GBK"));
            BufferedInputStream bufferedInputStream = new BufferedInputStream(zipInputStream);
            ZipEntry entry;
            byte[] file;
            while ((entry = zipInputStream.getNextEntry()) != null) {
                String pictureName = StringUtils.substringAfter(entry.getName(), "/");
                if (StringUtils.isNotEmpty(pictureName)) {
                    String prefix1 = StringUtils.left(pictureName, 7);
                    String prefix2 = StringUtils.left(pictureName, 8);
                    if (!(prefix1.equalsIgnoreCase(plateNum) || prefix2.equalsIgnoreCase(plateNum))) {
                        errmsg.append("图片命名与车牌号不符：" + pictureName).append("\r\n");
                        continue;
                    }
                    file = new byte[(int) entry.getSize()];
                    bufferedInputStream.read(file, 0, (int) entry.getSize());
                    MultipartFile image = new MockMultipartFile("file", pictureName, "text/plain", file);
                    String suffix = StringUtils.substringAfter(pictureName, ".");
                    pictureName = StringUtils.substringBefore(pictureName, ".");
                    ResponseData<String> ajaxList;
                    String uploadPath;
                    if ("pdf".equalsIgnoreCase(suffix)) {
                        ajaxList = UploadUtils.uploadFile(image, String.valueOf(adminParam.getAppid()), carDto.getPlateNum().replaceAll("[\\u4e00-\\u9fa5]", ""));
                    } else {
                        ajaxList = UploadUtils.uploadImage(image, String.valueOf(adminParam.getAppid()), carDto.getPlateNum().replaceAll("[\\u4e00-\\u9fa5]", ""), suffix);
                    }
                    if (!ajaxList.isSuccess()) {
                        ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, ajaxList.getMsg());
                    }
                    uploadPath = ajaxList.getData();
                    //设置图片路径
                    if (pictureName.equals(plateNum + "cl")) {
                        carDto.setCarImage(uploadPath);
                    } else if (pictureName.equals(plateNum + "cp")) {
                        carDto.setPlateImage(uploadPath);
                    } else if (pictureName.equals(plateNum + "xsz1")) {
                        carDto.setDrivingLicenseImg(uploadPath);
                    } else if (pictureName.equals(plateNum + "xsz2")) {
                        carDto.setDrivingLicenseSubImg(uploadPath);
                    } else if (pictureName.equals(plateNum + "jdk")) {
                        carDto.setMonitoringCardImg(uploadPath);
                    } else if (pictureName.equals(plateNum + "rchy")) {
                        carDto.setManCarImg(uploadPath);
                    } else if (pictureName.equals(plateNum + "yyz")) {
                        carDto.setOperationCertificateImg(uploadPath);
                    } else {
                        errmsg.append("图片命名错误：" + pictureName).append("\r\n");
                    }
                }
            }
            // 检查是否全部是必填项了
            String requireColumn = checkRequireColumn(carDto);
            if (StringUtils.isEmpty(requireColumn)) {
                carDto.setState(1);
            } else {
                errmsg.append(requireColumn);
            }
            carService.edit(carDto);
        } else {
            errmsg.append(plateNum + "该车辆不存在").append("\r\n");
        }
        String str = errmsg.toString();
        if (StringUtils.isEmpty(str)) {
            return ResponseData.buildSuccessResponse("导入成功", Boolean.TRUE);
        } else {
            return ResponseData.buildErrorResponse(ResponseData.ERROR_CODE, str);
        }
    }

    private String checkRequireColumn(CarDto dto) {
        StringBuilder errmsg = new StringBuilder();
        Integer businessType = dto.getBusinessType();
        if (businessType == CommonConstant.BUSINESS_TYPE_TAXI) {
            if (StringUtils.isEmpty(dto.getDrivingLicenseImg())) {
                errmsg.append("缺少图片：" + dto.getPlateNum() + "xsz1.jpg").append("\r\n");
            }
            if (StringUtils.isEmpty(dto.getDrivingLicenseSubImg())) {
                errmsg.append("缺少图片：" + dto.getPlateNum() + "xsz2.jpg").append("\r\n");
            }
            if (StringUtils.isEmpty(dto.getOperationCertificateImg())) {
                errmsg.append("缺少图片：" + dto.getPlateNum() + "yyz.jpg").append("\r\n");
            }
            if (StringUtils.isEmpty(dto.getMonitoringCardImg())) {
                errmsg.append("缺少图片：" + dto.getPlateNum() + "jdk.jpg").append("\r\n");
            }
            if (StringUtils.isEmpty(dto.getManCarImg())) {
                errmsg.append("缺少图片：" + dto.getPlateNum() + "rchy.jpg").append("\r\n");
            }
        }
        return errmsg.toString();
    }

    @RequestMapping(value = "/export", method = RequestMethod.POST)
    @ApiOperation(value = "导出车辆信息及对应的司机信息", httpMethod = "POST")
    public void exportCar(@RequestBody AdminCarPageParam carPageParam, HttpServletResponse response) throws Exception {
        try (OutputStream os = response.getOutputStream()) {
            List<CarExportVo> carList = carService.listExport(carPageParam).getData();
            InputStream in = getClass().getResourceAsStream("/template/carTemplate.xlsx");
            Workbook workbook = new XSSFWorkbook(in);
            // 获取司机导入格式面板
            Sheet sheet = workbook.getSheetAt(0);
            WorkbookUtil.writeDataToExcelBySheet(sheet, carList, CarImportVo.class);

            response.setHeader("Content-Disposition", "attachment; filename=" + java.net.URLEncoder.encode("car.xlsx", "UTF-8"));
            response.setContentType("application/octet-stream");
            response.setCharacterEncoding("utf-8");
            workbook.write(os);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    private CarImportVo readRowToBean(Row row) {
        CarImportVo carImportVo = new CarImportVo();
        int i = 0;
        carImportVo.setPlateNum(WorkbookUtil.getCellValue(row.getCell(i++)));
        carImportVo.setPlateColor(WorkbookUtil.getCellValue(row.getCell(i++)));
        carImportVo.setSeats(WorkbookUtil.getCellValue(row.getCell(i++)));
        carImportVo.setBrand(WorkbookUtil.getCellValue(row.getCell(i++)));
        carImportVo.setModel(WorkbookUtil.getCellValue(row.getCell(i++)));
        carImportVo.setCarColor(WorkbookUtil.getCellValue(row.getCell(i++)));
        carImportVo.setEngineId(WorkbookUtil.getCellValue(row.getCell(i++)));
        carImportVo.setVin(WorkbookUtil.getCellValue(row.getCell(i++)));
        carImportVo.setCertifyDateA(row.getCell(i++).getDateCellValue());
        carImportVo.setFuelType(WorkbookUtil.getCellValue(row.getCell(i++)));
        carImportVo.setEngineDisplace(WorkbookUtil.getCellValue(row.getCell(i++)));
        carImportVo.setEnginePower(WorkbookUtil.getCellValue(row.getCell(i++)));
        carImportVo.setCertificate(WorkbookUtil.getCellValue(row.getCell(i++)));
        carImportVo.setTransAgency(WorkbookUtil.getCellValue(row.getCell(i++)));
        carImportVo.setTransDateStart(row.getCell(i++).getDateCellValue());
        carImportVo.setTransDateStop(row.getCell(i++).getDateCellValue());
        carImportVo.setCertifyDateB(row.getCell(i++).getDateCellValue());
        carImportVo.setRegisterDate(row.getCell(i++).getDateCellValue());
        carImportVo.setCommercialType(WorkbookUtil.getCellValue(row.getCell(i++)));
        carImportVo.setFixState(WorkbookUtil.getCellValue(row.getCell(i++)));
        carImportVo.setNextFixDate(row.getCell(i++).getDateCellValue());
        carImportVo.setCheckState(WorkbookUtil.getCellValue(row.getCell(i++)));
        carImportVo.setFeePrintId(WorkbookUtil.getCellValue(row.getCell(i++)));
        carImportVo.setGpsBrand(WorkbookUtil.getCellValue(row.getCell(i++)));
        carImportVo.setGpsModel(WorkbookUtil.getCellValue(row.getCell(i++)));
        carImportVo.setGpsImei(WorkbookUtil.getCellValue(row.getCell(i++)));
        carImportVo.setGpsInstallDate(row.getCell(i++).getDateCellValue());
        carImportVo.setVehicleTechnicalCondition(WorkbookUtil.getCellValue(row.getCell(i++)));
        carImportVo.setSafetyPerformance(WorkbookUtil.getCellValue(row.getCell(i++)));
        carImportVo.setInsurCom(WorkbookUtil.getCellValue(row.getCell(i++)));
        carImportVo.setInsurNum(WorkbookUtil.getCellValue(row.getCell(i++)));
        carImportVo.setInsurType(WorkbookUtil.getCellValue(row.getCell(i++)));
        carImportVo.setInsurCount(WorkbookUtil.getCellValue(row.getCell(i++)));
        carImportVo.setInsurEff(row.getCell(i++).getDateCellValue());
        carImportVo.setInsurExp(row.getCell(i++).getDateCellValue());
        carImportVo.setAgent(WorkbookUtil.getCellValue(row.getCell(i++)));
        carImportVo.setCompany(WorkbookUtil.getCellValue(row.getCell(i++)));
        carImportVo.setCarModelType(WorkbookUtil.getCellValue(row.getCell(i++)));
        carImportVo.setOwnerName(WorkbookUtil.getCellValue(row.getCell(i++)));
        carImportVo.setOwnerNameMobile(WorkbookUtil.getCellValue(row.getCell(i++)));
        return carImportVo;
    }

    /**
     * 校验传入的每一行的数据
     *
     * @param carImportVo 行数据
     * @param type
     * @return
     */
    private Boolean validateRow(CarImportVo carImportVo, Row row, int type) {
        boolean flag = true;
        CellStyle cellStyle = workbook.createCellStyle();
        cellStyle.setFillForegroundColor(HSSFColor.YELLOW.index);
        cellStyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
        cellStyle.setFillBackgroundColor(HSSFColor.YELLOW.index);
        //字段长度根据表结构限制来设置
        // 0：车牌号
        String plateNum = carImportVo.getPlateNum();
        if (StringUtils.isEmpty(plateNum) || !plateNum.matches("^[\\u4e00-\\u9fa5]{1}[A-Z]{1}[A-Z0-9]{5,6}$")) {
            setCellStyle(row, row.getCell(0), 0, cellStyle);
            flag = false;
        }
        // 1：车牌颜色 略
        // 2：核定载客位
        String seats = carImportVo.getSeats();
        if (StringUtils.isNotEmpty(seats) && seats.length() > 5) {
            row.getCell(2).setCellStyle(cellStyle);
            flag = false;
        }
        // 3：车辆厂牌
        String brand = carImportVo.getBrand();
        if (StringUtils.isNotEmpty(brand) && brand.length() > 64) {
            row.getCell(3).setCellStyle(cellStyle);
            flag = false;
        }
        // 4：车辆型号
        String model = carImportVo.getModel();
        if (StringUtils.isNotEmpty(model) && model.length() > 64) {
            row.getCell(4).setCellStyle(cellStyle);
            flag = false;
        }
        // 5：车身颜色
        String carColor = carImportVo.getCarColor();
        if (StringUtils.isNotEmpty(carColor) && carColor.length() > 10) {
            row.getCell(5).setCellStyle(cellStyle);
            flag = false;
        }
        // 6：发动机号
        String engineId = carImportVo.getEngineId();
        if (StringUtils.isNotEmpty(engineId) && engineId.length() > 32) {
            row.getCell(6).setCellStyle(cellStyle);
            flag = false;
        }
        // 7：车辆VIN码
        String vin = carImportVo.getVin();
        if (StringUtils.isNotEmpty(vin) && vin.length() > 17) {
            row.getCell(7).setCellStyle(cellStyle);
            flag = false;
        }
        // 8：车辆注册日期
        // 9：车辆燃料类型 略
        // 10：发动机排量
        String engineDisplace = carImportVo.getEngineDisplace();
        if (StringUtils.isNotEmpty(engineDisplace) && engineDisplace.length() > 32) {
            row.getCell(10).setCellStyle(cellStyle);
            flag = false;
        }
        // 11：发动机功率
        String enginePower = carImportVo.getEnginePower();
        if (StringUtils.isNotEmpty(enginePower) && enginePower.length() > 32) {
            row.getCell(11).setCellStyle(cellStyle);
            flag = false;
        }
        // 12：运输证字号（营运证号）
        String certificate = carImportVo.getCertificate();
        if (StringUtils.isNotEmpty(certificate) && (!certificate.matches("^[u4E00-\u9FA5a-zA-Z0-9]$")) && certificate.length() > 64) {
            row.getCell(12).setCellStyle(cellStyle);
            flag = false;
        }
        // 13：车辆运输证发证机构
        String transAgency = carImportVo.getTransAgency();
        if (StringUtils.isNotEmpty(transAgency) && transAgency.length() > 256) {
            row.getCell(13).setCellStyle(cellStyle);
            flag = false;
        }
        // 14：车辆运输证有效期起
        // 15：车辆运输证有效期止
        // 16：车辆初次登记日期
        // 17：报备日期
        // 18：服务类型 略
        // 19：车辆检修状态 略
        // 20：车辆下次年检时间
        // 21：车辆年度审检状态 略
        // 22：发票打印设备序列号
        String feePrintId = carImportVo.getFeePrintId();
        if (StringUtils.isNotEmpty(feePrintId) && feePrintId.length() > 32) {
            row.getCell(22).setCellStyle(cellStyle);
            flag = false;
        }
        // 23：卫星定位装备品牌
        String gpsBrand = carImportVo.getGpsBrand();
        if (StringUtils.isNotEmpty(gpsBrand) && carImportVo.getGpsBrand().length() > 256) {
            row.getCell(23).setCellStyle(cellStyle);
            flag = false;
        }
        // 24：卫星定位装置型号
        String gpsModel = carImportVo.getGpsModel();
        if (StringUtils.isNotEmpty(gpsModel) && gpsModel.length() > 64) {
            row.getCell(24).setCellStyle(cellStyle);
            flag = false;
        }
        // 25：卫星定位装置IMEI号
        String gpsImei = carImportVo.getGpsImei();
        if (StringUtils.isNotEmpty(gpsImei) && gpsImei.length() > 128) {
            row.getCell(25).setCellStyle(cellStyle);
            flag = false;
        }
        // 26：卫星定位设备安装日期
        // 27：车辆技术状况
        String vehicleTechnicalCondition = carImportVo.getVehicleTechnicalCondition();
        if (StringUtils.isNotEmpty(vehicleTechnicalCondition) && vehicleTechnicalCondition.length() > 256) {
            row.getCell(27).setCellStyle(cellStyle);
            flag = false;
        }
        // 28：安全性能情况
        String safetyPerformance = carImportVo.getSafetyPerformance();
        if (StringUtils.isNotEmpty(carImportVo.getSafetyPerformance()) && safetyPerformance.length() > 256) {
            row.getCell(28).setCellStyle(cellStyle);
            flag = false;
        }
        // 29：保险公司
        String insurCom = carImportVo.getInsurCom();
        if (StringUtils.isNotEmpty(insurCom) && insurCom.length() > 64) {
            row.getCell(29).setCellStyle(cellStyle);
            flag = false;
        }
        // 30：保险号
        String insurNum = carImportVo.getInsurNum();
        if (StringUtils.isNotEmpty(insurNum) && insurNum.length() > 64) {
            row.getCell(30).setCellStyle(cellStyle);
            flag = false;
        }
        // 31：保险类型
        String insurType = carImportVo.getInsurType();
        if (StringUtils.isNotEmpty(insurType) && insurType.length() > 32) {
            row.getCell(31).setCellStyle(cellStyle);
            flag = false;
        }
        // 32：保险金额
        String insurCount = carImportVo.getInsurCount();
        if (StringUtils.isNotEmpty(insurCount) && insurCount.length() > 9) {
            row.getCell(32).setCellStyle(cellStyle);
            flag = false;
        }
        // 33：保险生效日期
        // 34：保险失效日期
        // 35：所属代理
        if (StringUtils.isEmpty(carImportVo.getAgent())) {
            setCellStyle(row, row.getCell(35), 35, cellStyle);
            flag = false;
        }
        // 36：所属公司
        if (StringUtils.isEmpty(carImportVo.getCompany())) {
            setCellStyle(row, row.getCell(36), 36, cellStyle);
            flag = false;
        }
        // 37：级别类型
        if (StringUtils.isEmpty(carImportVo.getCarModelType())) {
            setCellStyle(row, row.getCell(37), 37, cellStyle);
            flag = false;
        }

        // 39：所属人
        String ownerName = carImportVo.getOwnerName();
        if (StringUtils.isNotEmpty(ownerName) && ownerName.length() > 64) {
            row.getCell(38).setCellStyle(cellStyle);
            flag = false;
        }
        // 40：所属人电话
        String ownerNameMobile = carImportVo.getOwnerNameMobile();
        if (StringUtils.isNotEmpty(ownerNameMobile) && !ValidateUtils.weakCheckMobile(ownerNameMobile)) {
            row.getCell(39).setCellStyle(cellStyle);
            flag = false;
        }

        // 37：所属业务
        // 出租车业务
        if (type == CommonConstant.BUSINESS_TYPE_TAXI) {
            if (StringUtils.isEmpty(carImportVo.getCertificate())) {
                setCellStyle(row, row.getCell(12), 12, cellStyle);
                flag = false;
            }
            // 其他业务
        } else {
            //核定载客位
            if (StringUtils.isEmpty(carImportVo.getSeats())) {
                setCellStyle(row, row.getCell(2), 2, cellStyle);
                flag = false;
            }
            //车辆厂牌
            if (StringUtils.isEmpty(carImportVo.getBrand())) {
                setCellStyle(row, row.getCell(3), 3, cellStyle);
                flag = false;
            }
            //车辆型号
            if (StringUtils.isEmpty(carImportVo.getModel())) {
                setCellStyle(row, row.getCell(4), 4, cellStyle);
                flag = false;
            }
            //车身颜色
            if (StringUtils.isEmpty(carImportVo.getCarColor())) {
                setCellStyle(row, row.getCell(5), 5, cellStyle);
                flag = false;
            }
        }
        return flag;
    }

    private void setCellStyle(Row row, Cell cell, Integer cellnum, CellStyle cellStyle) {
        if (cell == null) {
            row.createCell(cellnum).setCellStyle(cellStyle);
        } else {
            cell.setCellStyle(cellStyle);
        }
    }
}
